<template>
  <div class="sddl-tree-container">
    <remote-search :search-method="searchMethod" @change="queryRemoteData"></remote-search>
    <el-scrollbar ref="scroll" :wrap-style="stylesheet" wrap-class="sddl-tree-scroll-wrap" v-loading="loading">
      <!-- <div style="width:0;"><div> -->
        <!-- v-loading="loading" -->
      <el-tree
        ref="tree"
        @node-expand="nodeExpand"
        :expand-on-click-node="false"
        :default-expanded-keys="expands"
        :render-after-expand="false"
        @node-click="nodeClick"
        v-bind="$attrs"
        v-on="$listeners"
        node-key="id"
        accordion
        :data="treeData"
        :props="relation"
      >
        <!-- <template slot-scope="{node, data}"> -->
        <template slot-scope="{data}">
          <span v-if="!data.hasOwnProperty('_state_')" :class="treeNodeStatus?treeNodeFontColor(treeNodeStatus[data.id],data.type):''" :title="data.description">
            <!-- <sd-icon-svg class="item-icon" :icon-class="setIcon(data.type,data.id)"></sd-icon-svg> -->
            {{data.label}}
            <!-- <sd-icon-svg class="item-icon" icon-class="folder"></sd-icon-svg>
            <sd-icon-svg class="item-icon" icon-class="station"></sd-icon-svg>  -->
          </span>
          <span class="load-item" v-else-if="data._state_">
            <el-link class="reload" type="danger">加载失败,重新加载</el-link>
          </span>
          <span class="load-item" v-else>
            <i class="el-icon-loading"></i>
            正在加载...
          </span>
        </template>
      </el-tree>
      <!-- </div></div> -->
    </el-scrollbar>
  </div>
</template>

<script lang="ts">
import { Vue, Component, Prop, Emit } from 'vue-property-decorator'
import RemoteSearch from './components/search.vue'
import { TreeNodeDataModel, RelatedNodeDataModel, RemoteOptions } from './types'
import { Tree } from 'element-ui'
import { findNodeKey } from '@/utils/tree'
import { TreeData } from 'element-ui/types/tree'
import { debounce } from '@/utils/execut'
@Component({
  components: {
    RemoteSearch
  }
})
export default class SddlTree extends Vue {
  @Prop({ type: String, default: 'auto' }) height!: string
  @Prop({ type: Function, required: true }) searchMethod!: (str: string) => Promise<RemoteOptions[]>
  @Prop({ type: Function, required: true }) remoteMethod!: (id: string) => Promise<TreeNodeDataModel>
  @Prop({ type: Function, required: true }) lazyMethod!: (id: string) => Promise<TreeNodeDataModel[]>
  @Prop({ type: Function, required: false }) treeNodeDbclick!: (data: TreeNodeDataModel) => {}
  @Prop({ type: Boolean, default: true }) currentAutoInsertNode!: boolean // 是否自动选中插入节点， 在下拉树组件时使用
  @Prop({ required: false }) treeNodeStatus!:{[index:string]:string}

  private treeData: TreeNodeDataModel[] = []
  private loading = false
  private expands: string[] = [] // 默认展开节点的key的数组
  // 树节点显示字段对应
  private relation: object = {
    label: 'label',
    children: 'children'
  }

  // 设置滚动条位置的防抖方法
  private setScroll: Function = () => {}
  // 判断不同状态的文字颜色
  private treeNodeFontColor (status:string, type:string) {
    if (type === 'lbq') {
      if (status === '1') {
        return ''
      } else {
        return 'error'
      }
    }
  }

  // 用于配置不同type对应的icon图标
  private deviceOne = ['line', 'bus', 'transformer', 'breaker'];
  private setIcon (type:string, id:string) {
    if (type === 'mainStation') {
      return 'mainStation'
    } else if (this.deviceOne.indexOf(type) >= 0) {
      return 'deviceOne'
    } else if (type === 'lbq') {
      if (!this.treeNodeStatus) {
        return 'lbq'
      }
      if (this.treeNodeStatus?.[id] === '1') {
        return 'lbq-success'
        // return 'lbq';
      }
      return 'lbq-error'
      // return 'lbq';
    } else if (type === 'station') {
      return 'station'
    } else {
      return 'folder'
    }
  }

  // 树容器样式
  private get stylesheet () {
    return `max-height:${this.height};margin-bottom: -17px; margin-right: -17px;`
  }

  // 给数据添加加载状态标识
  private formatterData (data: TreeNodeDataModel[]): TreeNodeDataModel[] {
    for (let i = 0; i < data.length; i++) {
      const node = data[i]
      if (node.children && node.children.length) {
        this.formatterData(node.children)
      } else if (node.children) {
        const obj = { id: `${node.id}-test` }
        // 0:未加载 1：加载失败
        this.$set(obj, '_state_', 0)
        node.children.push(obj as any)
      }
    }
    return data
  }

  // 下拉选框组件将调用此方法
  // 搜索条件变化 获取搜索选中的id的所有父节点
  public queryRemoteData (value: string): Promise<any> {
    this.loading = true
    return this.remoteMethod(value).then(res => {
      this.loading = false
      this.insertRelatedNode(res, value)
      return res
    }).catch(err => {
      this.loading = false
      return err
    })
  }

  // 查找父节点变插入数据
  private insertRelatedNode (data: RelatedNodeDataModel, queryId: string) {
    this.expands = []
    // 查找相同节点
    const rootNode = this.getRootNode(data.id)
    // 如果存在相同节点
    if (!(data.children?.length === 0 && data.parent_id === 0)) { // 如果选中为根节点不执行插入过程
      if (rootNode) {
        const { id, children } = findNodeKey(rootNode, data)
        const node = this.formatterData(children)
        if (id && children.length) {
          const parent = (this.$refs.tree as Tree).getNode(id) as any
          this.insertNode(node, parent.data)
        } else if (id) {
          this.insertNode(data)
        }
      } else { // 直接插入根节点
        this.insertNode(data)
      }
    }
    // 展开节点
    this.$nextTick(() => {
      const afterNode = (this.$refs.tree as Tree).getNode(queryId) as any
      if (afterNode && afterNode.level > 1) {
        this.expands = [afterNode.parent.key]
        this.insertCurrentChange(afterNode.data)
      }
      // 根节点不再执行插入，afterNode可能未获取导致，获取执行插入也会导致子节点未能正确选中
      // else{
      //   console.log(data);
      //   this.insertCurrentChange(data);
      // }
      setTimeout(() => {
        this.setScroll()
      })
    })
  }

  // 设置滚动条位置
  private setScrollCallback () {
    const nodeDom = document.querySelector('.is-current') as HTMLElement
    console.log(nodeDom)
    if (nodeDom) { (this.$refs.scroll as any).wrap.scrollTop = nodeDom.offsetTop }
  }

  // 在插入节点后，返回选中的当前节点的详细信息
  @Emit('insert-current-change')
  private insertCurrentChange (data: RelatedNodeDataModel) {
    return data
  }

  // 在单选模式下，添加选中的
  // 查找树的根节点中相同的节点
  private getRootNode (nodeId: string): TreeNodeDataModel | null {
    let node: TreeNodeDataModel | null = null
    for (let i = 0; i < this.treeData.length; i++) {
      if (this.treeData[i].id === nodeId) {
        node = this.treeData[i]
        break
      }
    }
    return node
  }

  // 节点点击
  private nodeClick (data: TreeNodeDataModel, node: any) {
    // 当节点标识
    if (data._state_ === 1) {
      this.nodeExpand(node.parent.data)
    }
  }

  // 节点展开事件
  @Emit('node-expand')
  private nodeExpand (data: TreeNodeDataModel) {
    if (!this.isLoad(data)) return
    if (data.children && data.children[0]) { data.children[0]._state_ = 0 }
    this.getTreeNode(data.id, (children) => {
      this.insertNode(children, data)
    }, err => {
      if (data.children && data.children[0]) { data.children[0]._state_ = 1 }
    })
    return arguments
  }

  // 获取节点数据
  private getTreeNode (id = '-1', successCallback: (data: TreeNodeDataModel[]) => any, errorCallback?: (message: any) => any) {
    this.lazyMethod(id).then(res => {
      successCallback(res)
    }).catch(err => {
      errorCallback && errorCallback(err.message || '')
    })
  }

  // 插入数据
  @Emit('insert-node')
  private insertNode (children: TreeNodeDataModel[] | TreeNodeDataModel, parent?: TreeNodeDataModel) {
    if (!Array.isArray(children)) children = [children]
    children = this.formatterData(children)
    if (!parent) {
      this.treeData = [...children]
    } else {
      parent.children = []
      parent.children.push(...children)
    }
    return { children, parent }
  }

  // 判断是否存在子节点
  private isLoad (data: TreeNodeDataModel): boolean {
    if (data.children && data.children.length <= 1) {
      if (data.children[0]) { return data.children[0].hasOwnProperty('_state_') } else return true
    } else return false
  }

  created () {
    this.getTreeNode('-1', data => {
      this.insertNode(data)
    })
  }

  mounted () {
    this.hookMounted()
    this.setScroll = debounce(this.setScrollCallback, 500)
  }

  @Emit('hook-mounted')
  private hookMounted () {

  }
}
</script>

<style scoped lang="scss">
.sddl-tree-container {
  width: 100%;
  .error{
    color:rgb(212, 101, 101);
    font-weight: 600;
  }
}
.load-item,
.reload {
  font-size: 1.2rem;
}
</style>
<style lang="scss">
.sddl-tree-scroll-wrap {
  width: auto;
  max-height: 100px;
}
// .el-tree-node > .el-tree-node__children {
//   overflow: visible;
// }
</style>
